home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 27
/
CU Amiga Magazine's Super CD-ROM 27 (1998)(EMAP Images)(GB)[!][issue 1998-10].iso
/
CUCD
/
Sound
/
SPlayer
/
Socks5
/
src
/
lib
/
log.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-07-20
|
8KB
|
252 lines
/* Copyright (c) 1995,1996,1997 NEC Corporation. All rights reserved. */
/* */
/* The redistribution, use and modification in source or binary forms of */
/* this software is subject to the conditions set forth in the copyright */
/* document ("Copyright") included with this distribution. */
/*
* $Id: log.c,v 1.71.4.2 1998/07/19 22:34:12 wlu Exp $
*/
#define __NOLOGUPDATEPROTO
#include "socks5p.h"
#include "log.h" /* Prototypes & defines. */
#include "threads.h" /* MUTEX & THREAD_SELF */
void *S5LogDefaultHandle = NULL;
int S5LogShowThreadIDS = 0;
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#define VA_START(a, b) va_start((a), (b))
#define va_alist ...
#define va_dcl
#else
#include <varargs.h>
#define VA_START(a, b) va_start((a))
#endif
#ifdef HAVE_NL_TYPES_H
#include <nl_types.h>
#endif
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#ifndef LOG_DAEMON
#define LOG_DAEMON LOG_USER
#endif
#endif
typedef struct {
#ifdef HAVE_NL_TYPES_H
nl_catd catalog;
#define NL_START(x, y) (x)->catalog = catopen((y), 0)
#define NL_UPDATE(x, e, f) if ((x)->catalog != (nl_catd)-1) (f) = catgets((x)->catalog, 0, (e), (f))
#define NL_CLOSE(x) if ((x)->catalog != (nl_catd)-1) catclose((x)->catalog); (x)->catalog = (nl_catd)-1
#elif defined(HAVE_DGETTEXT)
char domain[MAXNAMELEN];
#define NL_START(x, y) strncpy((x)->domain, name, MAX(MAXNAMELEN, strlen(name))); (x)->domain[MAX(MAXNAMELEN, strlen(name))] = '\0'
#define NL_UPDATE(x, e, f) (f) = dgettext((x)->domain, (f))
#define NL_CLOSE(x)
#else
#define NL_START(x, y)
#define NL_UPDATE(x, e, f)
#define NL_CLOSE(x)
#endif
int level;
int how;
} S5LogHandle;
static void replacePercentM(const char *inbuffer, char *outbuffer, int olen) {
register const char *t2;
register char *t1, ch;
if (!outbuffer || !inbuffer) return;
for (t1 = outbuffer; (ch = *inbuffer) && t1-outbuffer < olen ; ++inbuffer)
if (inbuffer[0] == '%' && inbuffer[1] == 'm')
for (++inbuffer, t2 = strerror(GETERRNO()); (t2 && t1-outbuffer < olen) && (*t1 = *t2++); t1++);
else *t1++ = ch;
*t1 = '\0';
}
void S5LogvUpdate(const void *handle, int level, int msgID, const char *oformat, va_list pvar) {
#define FMT_BUFLEN 2*1024 + 2*10
char fmt_cpy[FMT_BUFLEN], format[FMT_BUFLEN];
S5LogHandle *h = (S5LogHandle *)handle;
int serrno = GETERRNO();
#ifndef VSNPRINTF
static FILE *tmpFile = NULL;
#endif
*fmt_cpy = '\0';
/* If S5LogHandle has not been initialized, do it before we start; */
/* Saves the mess of making sure it gets called ahead of time. */
if (h == NULL) {
S5LogStart(&S5LogDefaultHandle, -1, -1, "libsocks5");
h = (S5LogHandle *)S5LogDefaultHandle;
}
/* If the handle is invalid, don't log. */
/* If the maximum log level is too low for this message, don't log. */
/* If something that we call forces us to log a message, don't log. */
if (!h || !(h->how) || h->level == -1 || level > h->level) return;
/* Change the format if the message is in the catalog... */
NL_UPDATE(h, msgID, oformat);
if (!oformat) return;
/* Print the pid & maybe the thread id in format here. Skip forward if */
/* you don't want it later (e.g. if syslogging). */
sprintf(format, "%05d:", (int)getpid());
if (S5LogShowThreadIDS) sprintf(format+strlen(format), "%06d:", (int)THREAD_SELF());
strcat(format, " ");
replacePercentM(oformat, format + strlen(format), sizeof(format) - strlen(format));
#ifdef HAVE_VSNPRINTF
if (vsnprintf(fmt_cpy, FMT_BUFLEN-1, format, pvar) < 0) {
fmt_copy[FMT_BUFLEN-1] = '\0';
}
#else
/* Original idea for VSPRINTF verification courtesy of Sten Gunterbuer */
/* (sten@ERGON.CH) a la BUGTRAQ. Another solution is to use pipes or a */
/* temp file, but I'm not convinced it would be more efficient (2 laps */
/* through the formatting versus 1 and a bunch of byte copies through */
/* the kernel). */
/* */
/* Thanks to Zach Brown (zab@zabbo.net) for finding the problem... */
if (tmpFile == NULL && (tmpFile = tmpfile()) == NULL) {
sprintf(fmt_cpy, "ERROR: Unable to verify string for vsprintf");
if ((h->level - 1) > S5_LOG_INFO) h->level = S5_LOG_INFO;
else h->level--;
level = S5_LOG_ERROR;
} else if (vfprintf(tmpFile, format, pvar) > FMT_BUFLEN-1) {
sprintf(fmt_cpy, "ERROR: String verification failed when trying to log message with format: %s", format);
if ((h->level - 1) > S5_LOG_INFO) h->level = S5_LOG_INFO;
else h->level--;
level = S5_LOG_ERROR;
} else {
rewind(tmpFile);
vsprintf(fmt_cpy, format, pvar);
}
#endif
/* Log to the Local log facility, e.g. Stderr on Unix and maybe a window */
/* or something on NT. Neither system can deal with a NULL format so */
/* check that here too. */
if (h->how & S5_LOG_LOCAL && format) {
fprintf(stderr, "%s\n", fmt_cpy);
fflush(stderr);
}
/* Log to the system logging facility -- e.g. Syslog on Unix & the */
/* EventLog on Windows NT. */
if (h->how & S5_LOG_SYSTEM) {
#if defined(HAVE_SYSLOG_H) && defined(SYSLOG_FAC)
int slfac, offset = 6;
if (level == S5_LOG_ERROR) slfac = LOG_ERR;
else if (level == S5_LOG_INFO) slfac = LOG_NOTICE;
else if (level > S5_LOG_INFO && level < S5_LOG_DEBUG(5)) slfac = LOG_WARNING;
else if (level > S5_LOG_DEBUG(0) && level < S5_LOG_DEBUG(10)) slfac = LOG_NOTICE;
else if (level > S5_LOG_DEBUG(5) && level < S5_LOG_DEBUG(15)) slfac = LOG_INFO;
else if (level >= S5_LOG_DEBUG(15)) slfac = LOG_DEBUG;
/* skip "%05d:", and maybe another " " */
if (!S5LogShowThreadIDS) offset++;
syslog(slfac, fmt_cpy + offset);
#else
#endif
}
SETERRNO(serrno); /* restore errno, just in case...? */
return;
}
void S5LogUpdate(const void *handle, int level, int msgID, const char *format, va_alist) va_dcl {
va_list pvar;
#ifdef HAVE_STDARG_H
va_start(pvar, format);
#else
VA_START(pvar, format);
#endif
S5LogvUpdate(handle, level, msgID, format, pvar);
va_end(pvar);
}
void S5LogStart(void **vhp, int how, int level, const char *name) {
S5LogHandle **hp = (S5LogHandle **)vhp;
char buf[1024], *tmp;
/*
char tbuf[1024];
time_t now = time(NULL);
*/
sprintf(buf, "%s", name);
if (!(*hp) && ((*hp) = (S5LogHandle *)malloc(sizeof(S5LogHandle))) == NULL) {
/* no where to store things, so just skip it. */
return;
} else {
if (how == -1) {
(*hp)->how = 0;
if (getenv("SOCKS5_LOG_SYSLOG")) (*hp)->how |= S5_LOG_SYSTEM;
if (getenv("SOCKS5_LOG_STDERR")) (*hp)->how |= S5_LOG_LOCAL;
} else (*hp)->how = how;
if (level == -1) {
if ((tmp = getenv("SOCKS5_DEBUG"))) {
if (isdigit((int)*tmp)) (*hp)->level = S5_LOG_DEBUG(atoi(tmp));
else (*hp)->level = S5_LOG_DEBUG(25);
} else (*hp)->level = -1;
} else (*hp)->level = level;
NL_START(*hp, buf);
}
#if defined(HAVE_SYSLOG_H) && defined(SYSLOG_FAC)
/* Only the first person to call this gets to open the log, that way the */
/* monitor doesn't clobber the server's socks5 name in the logs. */
if ((*hp)->how & S5_LOG_SYSTEM){
static int logopened = 0;
if (!logopened) {
logopened = 1;
openlog(name, LOG_PID, SYSLOG_FAC);
}
}
#endif
/* Following code is commented out so that we can remove DontLoop... */
/*
if (restart && (*hp)->how != 0) {
MUTEX_LOCK(lt_mutex);
strftime(tbuf, sizeof(tbuf), "%c", REAL(localtime)(&now));
S5LogUpdate((*hp), S5_LOG_DEBUG(0), 0, "%s Logging (re)started at %s", name, tbuf);
MUTEX_UNLOCK(lt_mutex);
}
*/
}
void S5LogEnd(void *vh) {
S5LogHandle *h = (S5LogHandle *)vh;
if (!h) return;
NL_CLOSE(h);
#if defined(HAVE_SYSLOG_H) && defined(SYSLOG_FAC)
closelog();
#endif
free(h);
}